<script setup>
import { ref, computed } from 'vue';
import { CloseCircleOutlined, SearchOutlined } from '@ant-design/icons-vue';
import StaffList from './staff-list.vue';
import { REQU, useResp } from '@/net/requ';
const userInfo = JSON.parse(localStorage.getItem('userInfo'));
const props = defineProps(['visible', 'ids', 'staffTree']);
defineEmits(['update:visible', 'ok']);

const visible = ref(props.visible);

const tree = ref({
  currentNode: props.staffTree[0],
  selectedKeys: ['all'],
});

const params = ref({
  groupIds: '',
  orgId: userInfo?.orgId ?? '',
  queryString: '',
});

const staffs = ref([]);

getStaffs();

function getStaffs() {
  REQU(`/api/user/userList?${ new URLSearchParams(params.value) }`)
  .then(useResp({
    succ: result => {
      // 暂时取消筛选 groupId
      // staffs.value = result.data.filter(R.prop('groupId'))
      staffs.value = result.data;
    }
  }));
}

function handleSelectTreeNode(keys, e) {
  const newParams = node => {
    if ('all' == node.key) { return ({ groupIds: '' }) }

    return node.key.includes('group')
    ? ({ groupIds: node.children.map(R.prop('id')).join(',') })
    : ({ groupIds: node.id.toString() })
  }

  tree.value.currentNode.value = e.node;
  tree.value.selectedKeys.value = [e.node.key];
  Object.assign(params.value, newParams(e.node));
}

const selectedIds = ref(new Set(props.ids));
const isSelected = staff => selectedIds.value.has(staff.id);
const selected = computed(() => staffs.value.filter(isSelected));

const staffMatched = computed(() => {
  const matched = o => !params.value.groupIds || params.value.groupIds.includes(o.groupId);
  return staffs.value.filter(matched);
});

const staffSearched = computed(() => {
  const searched = R.compose( R.includes(params.value.queryString), R.prop('realName') );
  return R.filter(searched, staffMatched.value);
});

const selectedMatched = computed(() => staffMatched.value.filter(isSelected));
const selectedAll = computed(() => selectedMatched.value.length == staffMatched.value.length);
const indeterminate = computed(() => 0 < selectedMatched.value.length && selectedMatched.value.length < staffMatched.value.length);

/**
 * @param {InputEvent | 'delete'} aid
 * @param {string} id
 */
const handleChange = (aid, id) => {
  const Action = R.cond([
    [R.is(String), R.identity],
    [R.T, R.ifElse( R.path(['target', 'checked']), R.always('add'), R.always('delete') )],
  ]);

  const AsAddOrDel = R.compose( R.invoker(1), Action )(aid);
  const Ids = R.ifElse( R.equals('all'), R.always(R.pluck('id', staffSearched.value)), Array.of );

  R.forEach(AsAddOrDel(R.__, selectedIds.value), Ids(id));
};

const okText = computed(() => {
  const count = selectedIds.value.size ? `（${selectedIds.value.size}）` : '';
  return `确定${count}`;
});
</script>

<template>
  <a-modal
    v-model:visible="visible"
    centered
    :width="800"
    class="staff-dialog"
    title="选择标注人员"
    :ok-text="okText"
    @ok="() => {
      $emit('ok', selected);
      $emit('update:visible', false);
    }"
    @cancel="() => $emit('update:visible', false)">
    <a-tree
      v-model:selectedKeys="tree.selectedKeys"
      :tree-data="props.staffTree"
      @select="handleSelectTreeNode">
    </a-tree>

    <div class="staff-select">
      <header>
        <a-input v-model:value="params.queryString" allow-clear placeholder="输入编码或姓名搜索">
          <template #prefix><search-outlined style="color: rgb(181,181,181);" /></template>
        </a-input>

        <span style="color: #666;">{{ tree.currentNode.title }}</span>
        <a-checkbox
          :checked="selectedAll"
          :indeterminate="indeterminate"
          @change="event => handleChange(event, 'all')">
        </a-checkbox>
      </header>

      <staff-list :list="staffSearched">
        <template #fn="{ item }">
          <a-checkbox
            :checked="selectedMatched.includes(item)"
            @change="event => handleChange(event, item.id)">
          </a-checkbox>
        </template>
      </staff-list>
    </div>

    <div class="staff-selected">
      <header>已选择（{{ selectedIds.size }}）</header>
      <staff-list :list="selected">
        <template #fn="{ item }">
          <a-button @click="() => handleChange('delete', item.id)">
            <template #icon><close-circle-outlined /></template>
          </a-button>
        </template>
      </staff-list>
    </div>
  </a-modal>
</template>

<style>
.staff-dialog .ant-modal-body {
  display: flex;
  height: 300px;
}

.staff-dialog .ant-modal-body > * {
  flex: 1;
  border-right: 1px solid rgb(240,240,240);
}

.staff-dialog .ant-modal-body > *:not(:first-child) {
  display: flex;
  gap: 1em;
  flex-direction: column;
  padding-left: 1em;
  padding-right: 1em;
}

.staff-list {
  flex: 1;
  height: 0;
  overflow-y: auto;
}

.staff-select > header {
  display: flex;
  flex-wrap: wrap;
  row-gap: 0.5em;
  justify-content: space-between;
}

.staff-selected > header {
  padding-bottom: 1em;
  color: rgb(153,153,153);
}
</style>
